package org.setamv.springcloud;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.filters.FilterRegistry;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.ClassUtils;

import javax.annotation.PostConstruct;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication
{
    public static void main( String[] args )
    {
        new SpringApplicationBuilder(ZuulApplication.class).web(true).run(args);
    }

    @Value("${server.port:8080}")
    private Integer serverPort;

    @Value("${tomcat.maxConnections:2000}")
    private Integer maxConnections;

    @Value("${tomcat.maxThreads:2000}")
    private Integer maxThreads;

    @Value("${tomcat.connectionTimeout:30000}")
    private Integer connectionTimeout;

    /**
     * spring boot容器初始化完成后，删除{@link FormBodyWrapperFilter}，该filter在zuul里面是多余的
     * <p>{@link FormBodyWrapperFilter}在执行过滤的过程中，该类会调用 {@link Jackson2ObjectMapperBuilder#registerWellKnownModulesIfAvailable(ObjectMapper)}
     * 然后{@link Jackson2ObjectMapperBuilder#registerWellKnownModulesIfAvailable(ObjectMapper)}会调用{@link ClassUtils#isPresent(String, ClassLoader)}方法，该方法使用了同步锁
     * @return
     */
    @Bean
    public ApplicationListener<ContextRefreshedEvent> startup() {
        return (ctx) -> {
            if (FilterRegistry.instance().get("formBodyWrapperFilter") != null) {
                FilterRegistry.instance().remove("formBodyWrapperFilter");
            }
        };
    }

    @Bean
    public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory()
    {
        TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
        tomcatFactory.setPort(serverPort);
        tomcatFactory.addConnectorCustomizers(connector -> {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            //设置最大连接数
            protocol.setMaxConnections(maxConnections);
            //设置最大线程数
            protocol.setMaxThreads(maxThreads);
            protocol.setConnectionTimeout(connectionTimeout);
        });
        return tomcatFactory;
    }
}
